home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / perl5 / RPC / XML / Parser.pm < prev    next >
Encoding:
Perl POD Document  |  2008-09-29  |  22.4 KB  |  668 lines

  1. ###############################################################################
  2. #
  3. # This file copyright (c) 2001-2008 Randy J. Ray, all rights reserved
  4. #
  5. # See "LICENSE" in the documentation for licensing and redistribution terms.
  6. #
  7. ###############################################################################
  8. #
  9. #   $Id: Parser.pm 363 2008-09-29 10:56:48Z rjray $
  10. #
  11. #   Description:    This is the RPC::XML::Parser class, a container for the
  12. #                   XML::Parser class. It was moved here from RPC::XML in
  13. #                   order to reduce the weight of that module.
  14. #
  15. #   Functions:      new
  16. #                   parse
  17. #                   message_init
  18. #                   message_end
  19. #                   tag_start
  20. #                   error
  21. #                   stack_error
  22. #                   tag_end
  23. #                   char_data
  24. #                   extern_ent
  25. #                   final
  26. #
  27. #   Libraries:      RPC::XML
  28. #                   XML::Parser
  29. #
  30. #   Global Consts:  Uses $RPC::XML::ERROR
  31. #
  32. #   Environment:    None.
  33. #
  34. ###############################################################################
  35.  
  36. package RPC::XML::Parser;
  37.  
  38. use 5.005;
  39. use strict;
  40. use vars qw($VERSION @ISA);
  41. use subs qw(error stack_error new message_init message_end tag_start tag_end
  42.             final char_data parse);
  43.  
  44. # These constants are only used by the internal stack machine
  45. use constant PARSE_ERROR => 0;
  46. use constant METHOD      => 1;
  47. use constant METHODSET   => 2;
  48. use constant RESPONSE    => 3;
  49. use constant RESPONSESET => 4;
  50. use constant STRUCT      => 5;
  51. use constant ARRAY       => 6;
  52. use constant DATATYPE    => 7;
  53. use constant ATTR_SET    => 8;
  54. use constant METHODNAME  => 9;
  55. use constant VALUEMARKER => 10;
  56. use constant PARAMSTART  => 11;
  57. use constant PARAM       => 12;
  58. use constant STRUCTMEM   => 13;
  59. use constant STRUCTNAME  => 14;
  60. use constant DATAOBJECT  => 15;
  61. use constant PARAMLIST   => 16;
  62. use constant NAMEVAL     => 17;
  63. use constant MEMBERENT   => 18;
  64. use constant METHODENT   => 19;
  65. use constant RESPONSEENT => 20;
  66. use constant FAULTENT    => 21;
  67. use constant FAULTSTART  => 22;
  68.  
  69. # This is to identify valid types
  70. use constant VALIDTYPES  => { map { $_, 1 } qw(int i4 i8 string double
  71.                                                boolean dateTime.iso8601
  72.                                                base64) };
  73. # This maps XML tags to stack-machine tokens
  74. use constant TAG2TOKEN   => { methodCall        => METHOD,
  75.                               methodResponse    => RESPONSE,
  76.                               methodName        => METHODNAME,
  77.                               params            => PARAMSTART,
  78.                               param             => PARAM,
  79.                               value             => VALUEMARKER,
  80.                               fault             => FAULTSTART,
  81.                               array             => ARRAY,
  82.                               struct            => STRUCT,
  83.                               member            => STRUCTMEM,
  84.                               name              => STRUCTNAME  };
  85.  
  86. # Members of the class
  87. use constant {
  88.     M_STACK                => 0,
  89.     M_CDATA                => 1,
  90.     M_BASE64_TO_FH         => 2,
  91.     M_BASE64_TEMP_DIR      => 3,
  92.     M_SPOOLING_BASE64_DATA => 4,
  93. };
  94.  
  95. use XML::Parser;
  96. require File::Spec;
  97.  
  98. require RPC::XML;
  99.  
  100. $VERSION = '1.16';
  101.  
  102. ###############################################################################
  103. #
  104. #   Sub Name:       new
  105. #
  106. #   Description:    Constructor. Save any important attributes, leave the
  107. #                   heavy lifting for the parse() routine and XML::Parser.
  108. #
  109. #   Arguments:      NAME      IN/OUT  TYPE      DESCRIPTION
  110. #                   $class    in      scalar    Class we're initializing
  111. #                   %attr     in      hash      Any extras the caller wants
  112. #
  113. #   Globals:        $RPC::XML::ERROR
  114. #
  115. #   Returns:        Success:    object ref
  116. #                   Failure:    undef
  117. #
  118. ###############################################################################
  119. sub new
  120. {
  121.     my $class = shift;
  122.     my %attrs = @_;
  123.  
  124.     my $self = [];
  125.  
  126.     while (my ($key, $val) = each %attrs)
  127.     {
  128.         if ($key eq 'base64_to_fh')
  129.         {
  130.             $self->[M_BASE64_TO_FH] = $val;
  131.         }
  132.         elsif ($key eq 'base64_temp_dir')
  133.         {
  134.             $self->[M_BASE64_TEMP_DIR] = $val;
  135.         }
  136.     }
  137.  
  138.     bless $self, $class;
  139. }
  140.  
  141. ###############################################################################
  142. #
  143. #   Sub Name:       parse
  144. #
  145. #   Description:    Parse the requested string or stream. This behaves mostly
  146. #                   like parse() in the XML::Parser namespace, but does some
  147. #                   extra, as well.
  148. #
  149. #   Arguments:      NAME      IN/OUT  TYPE      DESCRIPTION
  150. #                   $self     in      ref       Object of this class
  151. #                   $stream   in      scalar    Either the string to parse or
  152. #                                                 an open filehandle of sorts
  153. #
  154. #   Returns:        Success:    ref to request or response object
  155. #                   Failure:    error string
  156. #
  157. ###############################################################################
  158. sub parse
  159. {
  160.     my ($self, $stream) = @_;
  161.  
  162.     my $parser = XML::Parser->new(Namespaces => 0, ParseParamEnt => 0,
  163.                                   Handlers =>
  164.                                   {
  165.                                    Init      => sub { message_init $self, @_ },
  166.                                    Start     => sub { tag_start    $self, @_ },
  167.                                    End       => sub { tag_end      $self, @_ },
  168.                                    Char      => sub { char_data    $self, @_ },
  169.                                    Final     => sub { final        $self, @_ },
  170.                                    ExternEnt => sub { extern_ent   $self, @_ },
  171.                                   });
  172.  
  173.     # If there is no stream given, then create an incremental parser handle
  174.     # and return it.
  175.     return $parser->parse_start() unless $stream;
  176.  
  177.     my $retval;
  178.     eval { $retval = $parser->parse($stream) };
  179.     return $@ if $@;
  180.  
  181.     $retval;
  182. }
  183.  
  184. # This is called when a new document is about to start parsing
  185. sub message_init
  186. {
  187.     my ($robj, $self) = @_;
  188.  
  189.     $robj->[M_STACK] = [];
  190.     $self;
  191. }
  192.  
  193. # This is called when the parsing process is complete
  194. sub final
  195. {
  196.     my ($robj, $self) = @_;
  197.  
  198.     # Look at the top-most marker, it'll need to be one of the end cases
  199.     my $marker = pop(@{$robj->[M_STACK]});
  200.     # There should be only on item on the stack after it
  201.     my $retval = pop(@{$robj->[M_STACK]});
  202.     # If the top-most marker isn't the error marker, check the stack
  203.     $retval = 'RPC::XML Error: Extra data on parse stack at document end'
  204.         if ($marker != PARSE_ERROR and (@{$robj->[M_STACK]}));
  205.  
  206.     $retval;
  207. }
  208.  
  209. # This gets called each time an opening tag is parsed
  210. sub tag_start
  211. {
  212.     my ($robj, $self, $elem, %attr) = @_;
  213.  
  214.     $robj->[M_CDATA] = [];
  215.     return if ($elem eq 'data');
  216.  
  217.     if (TAG2TOKEN->{$elem})
  218.     {
  219.         push(@{$robj->[M_STACK]}, TAG2TOKEN->{$elem});
  220.     }
  221.     elsif (VALIDTYPES->{$elem})
  222.     {
  223.         # All datatypes are represented on the stack by this generic token
  224.         push(@{$robj->[M_STACK]}, DATATYPE);
  225.         # If the tag is <base64> and we've been told to use filehandles, set
  226.         # that up.
  227.         if ($elem eq 'base64')
  228.         {
  229.             return unless ($robj->[M_BASE64_TO_FH]);
  230.             require Symbol;
  231.             my ($fh, $file) = (Symbol::gensym(), File::Spec->tmpdir);
  232.  
  233.             $file = $robj->[M_BASE64_TEMP_DIR] if ($robj->[M_BASE64_TEMP_DIR]);
  234.             $file  = File::Spec->catfile($file, 'b64' . $self->current_byte);
  235.             unless (open($fh, "+> $file"))
  236.             {
  237.                 push(@{$robj->[M_STACK]},
  238.                      "Error opening temp file for base64: $!", PARSE_ERROR);
  239.                 $self->finish;
  240.             }
  241.             unlink($file);
  242.             $robj->[M_CDATA] = $fh;
  243.             $robj->[M_SPOOLING_BASE64_DATA]= 1;
  244.         }
  245.     }
  246.     else
  247.     {
  248.         push(@{$robj->[M_STACK]},
  249.              "Unknown tag encountered: $elem", PARSE_ERROR);
  250.         $self->finish;
  251.     }
  252. }
  253.  
  254. # Very simple error-text generator, just to eliminate heavy reduncancy in the
  255. # next sub:
  256. sub error
  257. {
  258.     my ($robj, $self, $mesg, $elem) = @_;
  259.     $elem ||= '';
  260.  
  261.     my $fmt = $elem ?
  262.         '%s at document line %d, column %d (byte %d, closing tag %s)' :
  263.         '%s at document line %d, column %d (byte %d)';
  264.  
  265.     push(@{$robj->[M_STACK]},
  266.          sprintf($fmt, $mesg, $self->current_line, $self->current_column,
  267.                  $self->current_byte, $elem),
  268.          PARSE_ERROR);
  269.     $self->finish;
  270. }
  271.  
  272. # A shorter-cut for stack integrity errors
  273. sub stack_error
  274. {
  275.     my ($robj, $self, $elem) = @_;
  276.  
  277.     error($robj, $self, 'Stack corruption detected', $elem);
  278. }
  279.  
  280. # This is a hairy subroutine-- what to do at the end-tag. The actions range
  281. # from simply new-ing a datatype all the way to building the final object.
  282. sub tag_end
  283. {
  284.     my ($robj, $self, $elem) = @_;
  285.  
  286.     my ($op, $attr, $obj, $class, $list, $name, $err);
  287.  
  288.     return if ($elem eq 'data');
  289.     # This should always be one of the stack machine ops defined above
  290.     $op = pop(@{$robj->[M_STACK]});
  291.  
  292.     my $cdata = '';
  293.     if ($robj->[M_SPOOLING_BASE64_DATA])
  294.     {
  295.         $cdata = $robj->[M_CDATA];
  296.         seek $cdata, 0, 0;
  297.     }
  298.     elsif ($robj->[M_CDATA])
  299.     {
  300.         $cdata = join('', @{$robj->[M_CDATA]});
  301.     }
  302.  
  303.     # Decide what to do from here
  304.     if (VALIDTYPES->{$elem})
  305.     {
  306.         # This is the closing tag of one of the data-types.
  307.         $class = $elem;
  308.         # Cheaper than the regex that was here, and more locale-portable
  309.         $class = 'datetime_iso8601' if ($class eq 'dateTime.iso8601');
  310.         # Some minimal data-integrity checking
  311.         if ($class eq 'int' or $class eq 'i4' or $class eq 'i8')
  312.         {
  313.             return error($robj, $self, 'Bad integer data read')
  314.                 unless ($cdata =~ /^[-+]?\d+$/);
  315.         }
  316.         elsif ($class eq 'double')
  317.         {
  318.             return error($robj, $self, 'Bad floating-point data read')
  319.                 unless ($cdata =~
  320.                         # Taken from perldata(1)
  321.                         /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/);
  322.         }
  323.  
  324.         $class = "RPC::XML::$class";
  325.         # The string at the end is only seen by the RPC::XML::base64 class
  326.         $obj = $class->new($cdata, 'base64 already encoded');
  327.         return error($robj, $self, 'Error instantiating data object: ' .
  328.                             $RPC::XML::ERROR)
  329.             unless ($obj);
  330.         push(@{$robj->[M_STACK]}, $obj, DATAOBJECT);
  331.         if ($robj->[M_SPOOLING_BASE64_DATA])
  332.         {
  333.             $robj->[M_SPOOLING_BASE64_DATA] = 0;
  334.             $robj->[M_CDATA] = undef; # Doesn't close FH, $obj still holds it
  335.         }
  336.     }
  337.     elsif ($elem eq 'value')
  338.     {
  339.         # For <value></value>, there should already be a dataobject, or else
  340.         # the marker token in which case the CDATA is used as a string value.
  341.         if ($op == DATAOBJECT)
  342.         {
  343.             ($op, $obj) = splice(@{$robj->[M_STACK]}, -2);
  344.             return stack_error($robj, $self, $elem)
  345.                 unless ($op == VALUEMARKER);
  346.         }
  347.         elsif ($op == VALUEMARKER)
  348.         {
  349.             $obj = RPC::XML::string->new($cdata);
  350.         }
  351.         else
  352.         {
  353.             return error($robj, $self,
  354.                          'No datatype found within <value> container');
  355.         }
  356.  
  357.         push(@{$robj->[M_STACK]}, $obj, DATAOBJECT);
  358.     }
  359.     elsif ($elem eq 'param')
  360.     {
  361.         # Almost like above, since this is really a NOP anyway
  362.         return error($robj, $self, 'No <value> found within <param> container')
  363.             unless ($op == DATAOBJECT);
  364.         ($op, $obj) = splice(@{$robj->[M_STACK]}, -2);
  365.         return stack_error($robj, $self, $elem) unless ($op == PARAM);
  366.         push(@{$robj->[M_STACK]}, $obj, DATAOBJECT);
  367.     }
  368.     elsif ($elem eq 'params')
  369.     {
  370.         # At this point, there should be zero or more DATAOBJECT tokens on the
  371.         # stack, each with a data object right below it.
  372.         $list = [];
  373.         return stack_error($robj, $self, $elem)
  374.             unless ($op == DATAOBJECT or $op == PARAMSTART);
  375.         while ($op == DATAOBJECT)
  376.         {
  377.             unshift(@$list, pop(@{$robj->[M_STACK]}));
  378.             $op = pop(@{$robj->[M_STACK]});
  379.         }
  380.         # Now that we see something ! DATAOBJECT, it needs to be PARAMSTART
  381.         return stack_error($robj, $self, $elem) unless ($op == PARAMSTART);
  382.         push(@{$robj->[M_STACK]}, $list, PARAMLIST);
  383.     }
  384.     elsif ($elem eq 'fault')
  385.     {
  386.         # If we're finishing up a fault definition, there needs to be a struct
  387.         # on the stack.
  388.         return stack_error($robj, $self, $elem) unless ($op == DATAOBJECT);
  389.         ($op, $obj) = splice(@{$robj->[M_STACK]}, -2);
  390.         return error($robj, $self,
  391.                      'Only a <struct> value may be within a <fault>')
  392.             unless ($obj->isa('RPC::XML::struct'));
  393.  
  394.         $obj = RPC::XML::fault->new($obj);
  395.         return error($robj, $self, 'Unable to instantiate fault object: ' .
  396.                             $RPC::XML::ERROR)
  397.             unless $obj;
  398.         push(@{$robj->[M_STACK]}, $obj, FAULTENT);
  399.     }
  400.     elsif ($elem eq 'member')
  401.     {
  402.         # We need to see a DATAOBJECT followed by a STRUCTNAME
  403.         return stack_error($robj, $self, $elem) unless ($op == DATAOBJECT);
  404.         ($op, $obj) = splice(@{$robj->[M_STACK]}, -2);
  405.         return stack_error($robj, $self, $elem) unless ($op == STRUCTNAME);
  406.         # Get the name off the stack to clear the way for the STRUCTMEM marker
  407.         # under it
  408.         ($op, $name) = splice(@{$robj->[M_STACK]}, -2);
  409.         # Push the name back on, with the value and the new marker (STRUCTMEM)
  410.         push(@{$robj->[M_STACK]}, $name, $obj, STRUCTMEM);
  411.     }
  412.     elsif ($elem eq 'name')
  413.     {
  414.         # Fairly simple: just push the current content of CDATA on w/ a marker
  415.         push(@{$robj->[M_STACK]}, $cdata, STRUCTNAME);
  416.     }
  417.     elsif ($elem eq 'struct')
  418.     {
  419.         # Create the hash table in-place, then pass the ref to the constructor
  420.         $list = {};
  421.         # First off the stack needs to be STRUCTMEM or STRUCT
  422.         return stack_error($robj, $self, $elem)
  423.             unless ($op == STRUCTMEM or $op == STRUCT);
  424.         while ($op == STRUCTMEM)
  425.         {
  426.             # Next on stack (in list-order): name, value
  427.             ($name, $obj) = splice(@{$robj->[M_STACK]}, -2);
  428.             $list->{$name} = $obj;
  429.             $op = pop(@{$robj->[M_STACK]});
  430.         }
  431.         # Now that we see something ! STRUCTMEM, it needs to be STRUCT
  432.         return stack_error($robj, $self, $elem) unless ($op == STRUCT);
  433.         $obj = RPC::XML::struct->new($list);
  434.         return error($robj, $self,
  435.                      'Error creating a RPC::XML::struct object: ' .
  436.                      $RPC::XML::ERROR)
  437.             unless $obj;
  438.         push(@{$robj->[M_STACK]}, $obj, DATAOBJECT);
  439.     }
  440.     elsif ($elem eq 'array')
  441.     {
  442.         # This is similar in most ways to struct creation, save for the lack
  443.         # of naming for the elements.
  444.         # Create the list in-place, then pass the ref to the constructor
  445.         $list = [];
  446.         # Only DATAOBJECT or ARRAY should be visible
  447.         return stack_error($robj, $self, $elem)
  448.             unless ($op == DATAOBJECT or $op == ARRAY);
  449.         while ($op == DATAOBJECT)
  450.         {
  451.             unshift(@$list, pop(@{$robj->[M_STACK]}));
  452.             $op = pop(@{$robj->[M_STACK]});
  453.         }
  454.         # Now that we see something ! DATAOBJECT, it needs to be ARRAY
  455.         return stack_error($robj, $self, $elem) unless ($op == ARRAY);
  456.         $obj = RPC::XML::array->new($list);
  457.         return error($robj, $self,
  458.                      'Error creating a RPC::XML::array object: ' .
  459.                      $RPC::XML::ERROR)
  460.             unless $obj;
  461.         push(@{$robj->[M_STACK]}, $obj, DATAOBJECT);
  462.     }
  463.     elsif ($elem eq 'methodName')
  464.     {
  465.         return error($robj, $self,
  466.                      "<$elem> tag must immediately follow a <methodCall> tag")
  467.             unless ($robj->[M_STACK]->[$#{$robj->[M_STACK]}] == METHOD);
  468.         push(@{$robj->[M_STACK]}, $cdata, NAMEVAL);
  469.     }
  470.     elsif ($elem eq 'methodCall')
  471.     {
  472.         # A methodCall closing should have on the stack an optional PARAMLIST
  473.         # marker, a NAMEVAL marker, then the METHOD token from the
  474.         # opening tag. An ATTR_SET may follow the METHOD token.
  475.         if ($op == PARAMLIST)
  476.         {
  477.             ($op, $list) = splice(@{$robj->[M_STACK]}, -2);
  478.         }
  479.         else
  480.         {
  481.             $list = [];
  482.         }
  483.         if ($op == NAMEVAL)
  484.         {
  485.             ($op, $name) = splice(@{$robj->[M_STACK]}, -2);
  486.         }
  487.         return error($robj, $self,
  488.                      "No methodName tag detected during methodCall parsing")
  489.             unless $name;
  490.         return stack_error($robj, $self, $elem) unless ($op == METHOD);
  491.         # Create the request object and push it on the stack
  492.         $obj = RPC::XML::request->new($name, @$list);
  493.         return error($robj, $self,
  494.                      "Error creating request object: $RPC::XML::ERROR")
  495.             unless $obj;
  496.         push(@{$robj->[M_STACK]}, $obj, METHODENT);
  497.     }
  498.     elsif ($elem eq 'methodResponse')
  499.     {
  500.         # A methodResponse closing should have on the stack only the
  501.         # DATAOBJECT marker, then the RESPONSE token from the opening tag.
  502.         if ($op == PARAMLIST)
  503.         {
  504.             # To my knowledge, the XML-RPC spec limits the params list for
  505.             # a response to exactly one object. Extract it from the listref
  506.             # and put it back.
  507.             $list = pop(@{$robj->[M_STACK]});
  508.             return error($robj, $self,
  509.                          "Params list for <$elem> tag invalid")
  510.                 unless (@$list == 1);
  511.             $obj = $list->[0];
  512.             return error($robj, $self,
  513.                          "Returned value on stack not a type reference")
  514.                 unless (ref $obj and $obj->isa('RPC::XML::datatype'));
  515.             push(@{$robj->[M_STACK]}, $obj);
  516.         }
  517.         elsif (! ($op == DATAOBJECT or $op == FAULTENT))
  518.         {
  519.             return error($robj, $self,
  520.                          "No parameter was declared for the <$elem> tag");
  521.         }
  522.         ($op, $list) = splice(@{$robj->[M_STACK]}, -2);
  523.         return stack_error($robj, $self, $elem) unless ($op == RESPONSE);
  524.         # Create the response object and push it on the stack
  525.         $obj = RPC::XML::response->new($list);
  526.         return error($robj, $self,
  527.                      "Error creating response object: $RPC::XML::ERROR")
  528.             unless $obj;
  529.         push(@{$robj->[M_STACK]}, $obj, RESPONSEENT);
  530.     }
  531. }
  532.  
  533. # This just spools the character data until a closing tag makes use of it
  534. sub char_data
  535. {
  536.      my ($robj, undef, $data) = @_;
  537.  
  538.      if ($robj->[M_SPOOLING_BASE64_DATA])
  539.      {
  540.          print {$robj->[M_CDATA]} $data;
  541.      }
  542.      else
  543.      {
  544.          push @{$robj->[M_CDATA]}, $data;
  545.      }
  546. }
  547.  
  548. # At some future point, this may be expanded to provide more entities than
  549. # just the four basic XML ones.
  550. sub extern_ent
  551. {
  552.     my $robj = shift;
  553.  
  554.     local $" = ', ';
  555.     warn ref($robj) . '::extern_ent: Attempt to reference external entity ' .
  556.         "(@_)\n";
  557.     return '';
  558. }
  559.  
  560. 1;
  561.  
  562. __END__
  563.  
  564. =head1 NAME
  565.  
  566. RPC::XML::Parser - A container class for XML::Parser
  567.  
  568. =head1 SYNOPSIS
  569.  
  570.     use RPC::XML::Parser;
  571.     ...
  572.     $P = RPC::XML::Parser->new();
  573.     $P->parse($message);
  574.  
  575. =head1 DESCRIPTION
  576.  
  577. The B<RPC::XML::Parser> class encapsulates the parsing process, for turning a
  578. string or an input stream into a B<RPC::XML::request> or B<RPC::XML::response>
  579. object. The B<XML::Parser> class is used internally, with a new instance
  580. created for each call to C<parse> (detailed below). This allows the
  581. B<RPC::XML::Parser> object to be reusable, even though the B<XML::Parser>
  582. objects are not. The methods are:
  583.  
  584. =over 4
  585.  
  586. =item new([ARGS])
  587.  
  588. Create a new instance of the class. Any extra data passed to the constructor
  589. is taken as key/value pairs (B<not> a hash reference) and attached to the
  590. object.
  591.  
  592. The following parameters are currently recognized:
  593.  
  594. =over 8
  595.  
  596. =item base64_to_fh
  597.  
  598. If passed with a true value, this tells the parser that incoming Base64 data
  599. is to be spooled to a filehandle opened onto an anonymous temporary file. The
  600. file itself is unlinked after opening, though the resulting B<RPC::XML::base64>
  601. object can use its C<to_file> method to save the data to a specific file at a
  602. later point. No checks on size are made; if this option is set, B<all> Base64
  603. data goes to filehandles.
  604.  
  605. =item base64_temp_dir
  606.  
  607. If this argument is passed, the value is taken as the directory under which
  608. the temporary files are created. This is so that the application is not locked
  609. in to the list of directories that B<File::Spec> defaults to with its
  610. C<tmpdir> method. If this is not passed, the previously-mentioned method is
  611. used to derive the directory in which to create the temporary files. Only
  612. relevant if B<base64_to_fh> is set.
  613.  
  614. =back
  615.  
  616. =item parse [ { STRING | STREAM } ]
  617.  
  618. Parse the XML document specified in either a string or a stream. The stream
  619. may be any file descriptor, derivative of B<IO::Handle>, etc. The return
  620. value is either an object reference (to one of B<RPC::XML::request> or
  621. B<RPC::XML::response>) or an error string. Any non-reference return value
  622. should be treated as an error condition.
  623.  
  624. If no argument is given, then the C<parse_start> method of B<XML::Parser> is
  625. used to create a B<XML::Parser::ExpatNB> object, which is returned. This
  626. object may then be used to parse the data in chunks, rather than a steady
  627. stream. See the B<XML::Parser> manual page for more details on how this
  628. works.
  629.  
  630. =back
  631.  
  632. =head1 DIAGNOSTICS
  633.  
  634. The constructor returns C<undef> upon failure, with the error message available
  635. in the global variable B<C<$RPC::XML::ERROR>>.
  636.  
  637. =head1 CAVEATS
  638.  
  639. This began as a reference implementation in which clarity of process and
  640. readability of the code took precedence over general efficiency. It is now
  641. being maintained as production code, but may still have parts that could be
  642. written more efficiently.
  643.  
  644. =head1 CREDITS
  645.  
  646. The B<XML-RPC> standard is Copyright (c) 1998-2001, UserLand Software, Inc.
  647. See <http://www.xmlrpc.com> for more information about the B<XML-RPC>
  648. specification.
  649.  
  650. =head1 LICENSE
  651.  
  652. This module and the code within are released under the terms of the Artistic
  653. License 2.0
  654. (http://www.opensource.org/licenses/artistic-license-2.0.php). This code may
  655. be redistributed under either the Artistic License or the GNU Lesser General
  656. Public License (LGPL) version 2.1
  657. (http://www.opensource.org/licenses/lgpl-license.php).
  658.  
  659. =head1 SEE ALSO
  660.  
  661. L<RPC::XML>, L<RPC::XML::Client>, L<RPC::XML::Server>, L<XML::Parser>
  662.  
  663. =head1 AUTHOR
  664.  
  665. Randy J. Ray <rjray@blackperl.com>
  666.  
  667. =cut
  668.